use std::cell::RefCell;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::rc::Rc;

use lazy_static::lazy_static;

use crate::common::Real;
use crate::common::{CooMatrix, CsrMatrix};

lazy_static! {
    pub static ref A: CsrMatrix = CsrMatrix::new();
}

pub fn read_coo_matrix(file_path: &str) -> Result<CooMatrix, std::io::Error> {
    let file = File::open(file_path)?;
    let reader = BufReader::new(file);
    let mut lines_iter = reader.lines().map(|l| l.unwrap());

    // 跳过以%开头的注释行
    while let Some(line) = lines_iter.next() {
        if !line.starts_with('%') {
            // 读取矩阵的行数、列数和非零元素数
            let parts: Vec<&str> = line.split_whitespace().collect();
            let rows: usize = parts[0].parse().unwrap();
            let cols: usize = parts[1].parse().unwrap();
            let nnz: usize = parts[2].parse().unwrap();

            // 读取每个非零元素所在的行列以及值
            let mut data = Vec::new();
            let mut row_indices = Vec::new();
            let mut col_indices = Vec::new();

            for _ in 0..nnz {
                let line = lines_iter.next().unwrap();
                let parts: Vec<&str> = line.split_whitespace().collect();
                let row: usize = parts[0].parse().unwrap();
                let col: usize = parts[1].parse().unwrap();
                let value: f64 = parts[2].parse().unwrap();

                row_indices.push(row - 1);
                col_indices.push(col - 1);
                data.push(value);
            }

            return Ok(CooMatrix {
                row_index: row_indices,
                col_index: col_indices,
                value: data,
                num_rows: rows,
                num_cols: cols,
                nnz: nnz,
            });
        }
    }

    Err(std::io::Error::new(
        std::io::ErrorKind::InvalidData,
        "Invalid matrix format",
    ))
}
fn print_coo(coo: CooMatrix) {
    print!("row_ptr=\n");
    for i in coo.row_index {
        print!("{} ", i);
    }
}
fn coo_to_csr(coo_matrix: &CooMatrix, csr_matrix: &mut CsrMatrix) {
    // csr_matrix = CsrMatrix {
    //     col_index: vec![0; coo_matrix.nnz],
    //     row_ptr: vec![0; coo_matrix.num_rows + 1],
    //     value: vec![0.0; coo_matrix.nnz],
    //     num_rows: coo_matrix.num_rows,
    //     num_cols: coo_matrix.num_cols,
    //     nnz: coo_matrix.nnz,
    // };
    csr_matrix.col_index = vec![0; coo_matrix.nnz];
    csr_matrix.row_ptr = vec![0; coo_matrix.num_rows + 1];
    csr_matrix.value = vec![0.0; coo_matrix.nnz];
    csr_matrix.num_cols = coo_matrix.num_cols;
    csr_matrix.num_rows = coo_matrix.num_rows;
    csr_matrix.nnz = coo_matrix.nnz;

    // 计算每行非零元素的个数
    let mut row_counts = vec![0; coo_matrix.num_rows];
    for &row in &coo_matrix.row_index {
        row_counts[row] += 1;
    }

    // 计算每行的累积非零元素个数
    for i in 1..coo_matrix.num_rows {
        csr_matrix.row_ptr[i] = csr_matrix.row_ptr[i - 1] + row_counts[i - 1];
    }
    csr_matrix.row_ptr[coo_matrix.num_rows] = coo_matrix.nnz;

    // 将COO格式的数据转换为CSR格式
    let mut row_start = vec![0; coo_matrix.num_rows];
    for i in 0..coo_matrix.nnz {
        let row = coo_matrix.row_index[i];
        csr_matrix.col_index[csr_matrix.row_ptr[row] + row_start[row]] = coo_matrix.col_index[i];
        csr_matrix.value[csr_matrix.row_ptr[row] + row_start[row]] = coo_matrix.value[i];
        row_start[row] += 1;
    }
}

fn print_csr(csr: &CsrMatrix) {
    print!("row_ptr\n");
    for i in &csr.row_ptr {
        print!("{} ", i);
    }
    print!("col_index\n");
    for i in &csr.col_index {
        print!("{} ", i);
    }
    print!("value\n");
    for i in &csr.value {
        print!("{} ", i);
    }
}
fn spmv(csr_matrix: &CsrMatrix, x: &[Real], y: &mut [Real]) {
    assert_eq!(csr_matrix.num_cols, x.len());
    assert_eq!(csr_matrix.num_rows, y.len());

    for i in 0..csr_matrix.num_rows {
        let mut sum = 0.0;
        for j in csr_matrix.row_ptr[i]..csr_matrix.row_ptr[i + 1] {
            let col = csr_matrix.col_index[j];
            let val = csr_matrix.value[j];
            sum += val * x[col];
        }
        y[i] = sum;
    }
}
impl CsrMatrix {
    pub fn create_host_data(&mut self, file_name: &str) {
        // let file_name: String =
        //     //"/home/xjb/Desktop/code/spmv-acc-cuda/src/coo_data/torso2.mtx".to_string();
        //     "/home/xjb/Desktop/code/Benchmark_SpMV_using_CSR5/CSR5_avx2/Freescale1.mtx".to_string();
        let coo = read_coo_matrix(file_name).unwrap();
        //print_coo(coo);
        let mut tA = CsrMatrix::new();
        coo_to_csr(&coo, &mut tA);
        //print_csr(&csr);
        // let mut x: Vec<Vec<Real>> = vec![vec![0.0; A.num_rows]; 10];
        // let mut y: Vec<Vec<Real>> = vec![vec![0.0; A.num_rows]; 10];

        // for i in 0..10 {
        //     for j in &mut x[i] {
        //         *j = 1.0;
        //     }
        //     let start = std::time::Instant::now();
        //     spmv(&A, &x[i], &mut y[i]);
        //     let duration = start.elapsed();
        //     print!("{} time:{:?} \n", i, duration);
        // }

        // print!("result\n");
        // for i in y{
        //     print!("{} ",i);
        // }
        unsafe {
            A = tA;
        }
    }
}
impl CsrMatrix {
    pub fn calc(&self) {
        let mut x: Vec<Vec<Real>> = vec![vec![0.0; self.num_rows]; 10];
        let mut y: Vec<Vec<Real>> = vec![vec![0.0; self.num_rows]; 10];

        for i in 0..10 {
            for j in &mut x[i] {
                *j = 1.0;
            }
            let start = std::time::Instant::now();
            spmv(&self, &x[i], &mut y[i]);
            let duration = start.elapsed();
            print!("{} time:{:?} \n", i, duration);
        }
    }
}
fn create_device_data() {}
